
#include "Tools.h"

#include <sys/stat.h>

#include <cstring>
#include <iostream>
#include <string>

#ifdef _WIN32
#include <intrin.h>   // For __cpuid on Windows
#include <windows.h>  // For MAX_PATH and OPENFILENAME
#endif

#include "Utility/Logging/SGLogger.h"

#include "Main/ProgramInfo.h"

using SG::DataStructure::Common::Status;
using SG::DataStructure::FEM::Project;

void help ()
{
    const std::string output = R"(
    egg: SGFEM -i your/input/file/name [-w workspace] [-j project_name]
    命令参数含义：
    -i input file name 【必须非空， 模型文件名称, 包含路径】
    -w workspace      【可选参数，输出文件保存路径】
    -j porjectName    【可选参数，工程名称，输出文件名称】)";
    // 务必刷新缓存区
    std::cout << output << std::endl;
}

/**  @brief 输入软件启动提示
 *
 * @param input 输入文件名称
 */
void printSubmitPrompt (const std::string &input)
{
    const std::string head = R"(/***********************************************)";
    SGInfo << head;
    SGInfo << "Start " << PROGRAM_NAME << VERSION;
    SGInfo << "Job submited to local host ";
    SGInfo << "Input file: " << input << "\n";
}

void printEndPrompt (const std::string &job)
{
    SGInfo << "Job " << job << " Finish" << "\n";
    std::string end = R"(***********************************************/)";
    SGInfo << end;
}

SG::DataStructure::Common::Status parserCommond (int argc, char **argv, SG::DataStructure::FEM::Project &project)
{
    project         = Project ();
    auto nParameter = static_cast<std::size_t> ((argc - 1) / 2);

    bool hasInputFile{ false };
    bool hasProjectName{ false };
    bool hasWorkspace{ false };
    for (std::size_t iPara = 0; iPara < nParameter; ++iPara)
    {
        std::string option{ argv[iPara * 2 + 1] };

        if (0 == option.compare ("-s"))
        {
            project.showWidget = true;
            return Status::STATUS_Success;
        }

        if (0 == option.compare ("-i"))
        {
            std::string fullpath = std::string (argv[iPara * 2 + 2]);
            // 检查输入文件路径是否存在
            if (!isPathValidAndExists (fullpath))
            {
                SGError << "Error -- 请指定正确的输入文件路径 \n";
                return Status::STATUS_Failure;
            }

            // 分解路径为目录路径和文件名
            splitPath (fullpath, project.m_modelFilePath, project.m_modelFileName);

            hasInputFile = true;
        }

        if (0 == option.compare ("-w"))
        {
            std::string workpath = std::string (argv[iPara * 2 + 2]);
            // 检查工作路径是否存在，不存在则创建
            if (!isPathValidAndExists (workpath))
            {
                if (!createDirectories (workpath))
                {
                    SGError << "Error -- 请指定正确的工作文件 \n" << std::endl;
                    return Status::STATUS_Failure;
                }
            }

            if (!workpath.empty () && workpath.back () != '/' && workpath.back () != '\\')
            {
                workpath += "/";
            }

            project.m_workSpace = workpath;
            hasWorkspace        = true;
        }

        if (0 == option.compare ("-j"))
        {
            project.m_jobName = std::string (argv[iPara * 2 + 2]);
            hasProjectName    = true;
        }
    }

    if(argc == 2)
    {
        std::string option{ argv[1] };
        if (0 == option.compare ("-s"))
        {
            project.showWidget = true;
            return Status::STATUS_Success;
        }
    }
    // 缺少必须的求解参数。 模型文件名称
    if (!hasInputFile)
    {
        SGError << "Error -- 必须指定输入文件路径 \n";
        return Status::STATUS_Failure;
    }

    if (!hasWorkspace)
    {
        // 没有指定工作空间，工作空间和输入文件路径一致
        project.m_workSpace = project.m_modelFilePath;
    }

    if (!hasProjectName)
    {
        // 没有指定项目名称，默认项目名称与输入模型文件名称相同（去掉后缀）。
        auto imgName      = project.m_modelFileName;
        project.m_jobName = imgName.substr (0, imgName.rfind ("."));
    }

    return Status::STATUS_Success;
}

bool isPathValidAndExists (const std::string &path)
{
    struct stat buffer;
    return (stat (path.c_str (), &buffer) == 0);
}

bool createDirectory (const std::string &path)
{
    struct stat st = { 0 };
    if (stat (path.c_str (), &st) == -1)
    {
        int status;
#if defined(_WIN64) || defined(WIN32) || defined(_WIN32)
        status = mkdir (path.c_str ());
#else
        status = mkdir (path.c_str (), 0777);
#endif
        if (status == -1)
        {
            std::cerr << "Error creating directory: " << strerror (errno) << std::endl;
            return false;
        }
    }
    return true;
}

bool createDirectories (std::string &path)
{
    size_t      pos = 0;
    std::string currentPath;
    std::string delimiter = "/\\";

    // 如果路径不是以分隔符结尾，添加分隔符
    if (!path.empty () && path.back () != '/' && path.back () != '\\')
    {
        path += "/";
    }
    while ((pos = path.find_first_of (delimiter, pos)) != std::string::npos)
    {
        currentPath = path.substr (0, ++pos);
        if (!currentPath.empty () && !isPathValidAndExists (currentPath) && !createDirectory (currentPath))
            return false;
    }

    return createDirectory (path);
}
void splitPath (const std::string &fullPath, std::string &directoryPath, std::string &fileName)
{
    // 查找最后一个目录分隔符的位置
    size_t pos = fullPath.find_last_of ("/\\");
    if (pos != std::string::npos)
    {
        // 分割目录路径和文件名
        directoryPath = fullPath.substr (0, pos + 1);
        fileName      = fullPath.substr (pos + 1);
    }
    else
    {
        // 没有找到分隔符，假设整个路径就是文件名
        directoryPath = "./";
        fileName      = fullPath;
    }
}

bool checkCpuAndWarnIfAmd ()
{
    std::string cpuVendor = "";

#ifdef _WIN32
    // Windows平台使用CPUID指令
    int cpuInfo[4] = { 0 };
    __cpuid (cpuInfo, 0);

    // 提取厂商字符串
    char vendor[13]                       = { 0 };
    *reinterpret_cast<int *> (vendor)     = cpuInfo[1];  // EBX
    *reinterpret_cast<int *> (vendor + 4) = cpuInfo[3];  // EDX
    *reinterpret_cast<int *> (vendor + 8) = cpuInfo[2];  // ECX
    cpuVendor                             = std::string (vendor);

#elif defined(__GNUC__) || defined(__clang__)
    // Linux/GCC平台使用内联汇编
    unsigned int eax, ebx, ecx, edx;
    __asm__ __volatile__ ("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0));

    char vendor[13]                                = { 0 };
    *reinterpret_cast<unsigned int *> (vendor)     = ebx;
    *reinterpret_cast<unsigned int *> (vendor + 4) = edx;
    *reinterpret_cast<unsigned int *> (vendor + 8) = ecx;
    cpuVendor                                      = std::string (vendor);
#endif

    // 检查是否为AMD CPU
    if (cpuVendor == "AuthenticAMD")
    {
        SGWarn << "================================================================";
        SGWarn << "WARNING: AMD CPU detected!";
        SGWarn << "This program uses the Intel MKL mathematical library for solving calculations.";
        SGWarn << "On AMD platforms, have performance limitations or computational accuracy issues.";
        SGWarn << "================================================================";
        return true;
    }
    /* if (cpuVendor == "GenuineIntel")
    {
        SGInfo << "检测到Intel处理器，Intel MKL将提供最佳性能。";
    }
    else
    {
        SGInfo << "检测到其他厂商处理器: " << cpuVendor;
        SGWarn << "注意: 本程序针对Intel处理器和Intel MKL优化，在其他平台上性能可能受限。";
    } */

    return false;
}

#ifdef _WIN32
std::string OpenFileDialog ()
{
    char         szFile[MAX_PATH] = { 0 };
    OPENFILENAME ofn              = { 0 };
    ofn.lStructSize               = sizeof (OPENFILENAME);
    // ofn.hwndOwner = hwnd;
    /* 使用字符串数组来设定过滤器 */
    ofn.lpstrFilter = "Nastran bdf Files\0*.bdf\0Nastran dat Files\0*.dat\0All Files\0*.*\0";
    ofn.lpstrFile   = szFile;
    ofn.nMaxFile    = MAX_PATH;
    ofn.Flags       = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    if (GetOpenFileName (&ofn))
    {
        return szFile;
    }
    return "@";
}
#endif